<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Range Loading Video</title>
</head>
<body>
  <video id="video" controls autoplay></video>
  <button id="startButton">Start Video</button>
</body>

<script>
const mimeType = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
const video = document.getElementById("video");
const startButton = document.getElementById("startButton");
let mediaSource = new MediaSource();
const videoUrl = "//obs.ispm.vip/animation-rc/f45d78313ee8e18ec170f3e393f0b34a.mp4"; // 视频文件的URL
let sourceBuffer;
let videoSize = 0;
let isBuffering = false;
let start = 0;
let end = 2 * 1024 * 1024; // 初始分片设置为 1MB

startButton.addEventListener("click", () => {
  video.src = URL.createObjectURL(mediaSource);

  fetch(videoUrl, { method: "HEAD" })
    .then((response) => {
      if (!MediaSource.isTypeSupported(mimeType)) {
        console.error("Unsupported MIME type:", mimeType);
        return;
      }
      videoSize = parseInt(response.headers.get("Content-Length"));
      console.log("Video size:", videoSize, "bytes");

      mediaSource.addEventListener("sourceopen", () => {
        console.log("MediaSource opened");
        sourceBuffer = mediaSource.addSourceBuffer(mimeType);

        sourceBuffer.addEventListener("updateend", () => {
          console.log("SourceBuffer updateend");
          isBuffering = false;
        });

        startLoad();
      });
    })
    .catch((error) => console.error("Error fetching video metadata:", error));
});

// 加载视频片段
async function startLoad() {
  while (start < videoSize) {
    if (video.error) {
      console.error("Video element error detected:", video.error);
      break;
    }

    if (mediaSource.readyState !== "open") {
      console.error("MediaSource state is", mediaSource.readyState);
      break;
    }

    try {
      await loadNextSegment(start, end);
    } catch (error) {
      console.error("Error during segment loading:", error);
      break;
    }

    await new Promise((resolve) => setTimeout(resolve, 100));
    start = end + 1;
    end = Math.min(start + 2 * 1024 * 1024, videoSize); // 后续每次加载 1MB
  }
}

function loadNextSegment(start, end) {
  if (isBuffering || sourceBuffer.updating) {
    console.warn("Buffer is busy, skipping segment load");
    return Promise.reject(new Error("Buffer is busy"));
  }

  isBuffering = true;
  const range = `bytes=${start}-${Math.min(end - 1, videoSize - 1)}`;
  console.log(`Requesting range: ${range}`);

  return fetch(videoUrl, { headers: { Range: range } })
    .then((response) => {
      if (!response.ok) {
        throw new Error(`HTTP error: ${response.status}`);
      }
      return response.arrayBuffer();
    })
    .then((data) => {
      sourceBuffer.appendBuffer(data);
    })
    .catch((error) => {
      console.error("Error appending buffer:", error);
      throw error;
    })
    .finally(() => {
      isBuffering = false;
    });
}
</script>
</html>
